/*
 * BPlusTreeFixedTest_gtest.h
 *
 *  Created on: Nov 28, 2012
 *      Author: Federico Orquera
 */

#ifndef BPLUSTREEFIXEDTEST_GTEST_H_
#define BPLUSTREEFIXEDTEST_GTEST_H_

#include <string>
#include <sstream>
#include <gtest/gtest.h>

#include "../logic_layer/bplustree/BPlusTreeFixed.h"

/**
 * Test Suite de la clase SBPlusTreeFileHandler
 */

class BPlusTreeFixedTestFixture: public ::testing::Test
{
public:

	BPlusTreeFixedTestFixture()
    {
        /*
         * Acá lo único que hago es obtener el nombre
         * del TestFixture y del TestCase que se está ejecutando
         * y con eso armo un "filename" del tipo: testname.testcase.tmp
         */

        const ::testing::TestInfo* const test_info =
                ::testing::UnitTest::GetInstance()->current_test_info();

        std::string filename( test_info->name() );
        filename.append( "." );
        filename.append( test_info->test_case_name() );
        filename.append( ".tmp" );

        m_filename = filename;

        srand(time(NULL));

    }

    virtual ~BPlusTreeFixedTestFixture()
    {
    }

    void SetUp()
    {
    }

    void TearDown()
    {
    }

    /**
     * Devuelve un filename como: testname.testcase.tmp
     *
     * @return un filename predecible para usar en el test
     */
    const char* getFileNameForTest()
    {
        return m_filename.c_str();
    }

    /**
     * Genera un string aleatorio de longitud Lenght
     * @param length lalongitus del string
     * @return
     */
    string getRandomStr(int length = 10) {
        string charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
        string result;
        result.resize(length);

        for (unsigned int i = 0; i < result.length(); i++)
            result[i] = charset[rand() % charset.length()];

        return result;
    }

    std::string m_filename;
};

/**
 * Test Insert And Search
 */
TEST_F( BPlusTreeFixedTestFixture, InsertAndSearch)
{
	BPlusTreeFixed tree( this->getFileNameForTest(), 2 * 64, true );

	std::string  key = "asdkjaslkdja";

	tree.InsertRegister(key, {});

	auto queryResult = tree.SearchRegister(key);

	ASSERT_EQ(queryResult.result->getKey(), key);
}

/**
 * Test Multiple Insert
 */
TEST_F( BPlusTreeFixedTestFixture, MultipleInsert)
{
	BPlusTreeFixed tree( this->getFileNameForTest(), 2 * 64, true );

	std::string  base("asdasd"),key;
	std::list<std::string> keyList, treeList;

	for( int i = 0; i<300; i++ ){

		std::stringstream sstm;
		sstm << base << i;
		key = sstm.str();

		keyList.push_back(key);
		tree.InsertRegister(key,{});

	}

	keyList.sort();

	auto queryResult = tree.SearchRegister("a");

	for( ;!queryResult.endOfList
		 ;queryResult = tree.SearchNextRegister(queryResult)
	) treeList.push_back(queryResult.result->getKey());

	treeList.push_back(queryResult.result->getKey());

	ASSERT_EQ(treeList.size(), keyList.size());

	ASSERT_EQ(treeList, keyList);
}

/**
 * Test Multiple Insert
 */
TEST_F( BPlusTreeFixedTestFixture, MultipleInsertOpenClose )
{
	std::unique_ptr<BPlusTreeFixed> tree ( new BPlusTreeFixed( this->getFileNameForTest(), 2 * 64, true ) );

	std::string  base("asdasd"),key;
	std::list<std::string> keyList, treeList;

	for( int i = 0; i<300; i++ ){

		std::stringstream sstm;
		sstm << base << i;
		key = sstm.str();

		keyList.push_back(key);
		tree->InsertRegister(key, {});

	}

	keyList.sort();

	tree.reset( new BPlusTreeFixed( this->getFileNameForTest(), 2 * 64, false ) );

	auto queryResult = tree->SearchRegister("a");

	for(	;
			!queryResult.endOfList;
			queryResult = tree->SearchNextRegister(queryResult)
	) {
		treeList.push_back(queryResult.result->getKey());
	}

	treeList.push_back(queryResult.result->getKey());

	ASSERT_EQ(treeList.size(), keyList.size());

	ASSERT_EQ(treeList, keyList);
}

/**
 * Test Insert And Update
 */

TEST_F( BPlusTreeFixedTestFixture, InsertAndUpdate)
{
	BPlusTreeFixed tree( this->getFileNameForTest(), 2 * 64, true );

	std::string  key = this->getRandomStr();
	InvertedListPosition notUpdated(2), updated(666);

	tree.InsertRegister(key, {1,notUpdated});

	auto queryResult = tree.SearchRegister(key);

	ASSERT_EQ(queryResult.result->getValue().m_invertedListPosition, notUpdated);

	tree.UpdateRegister(key, updated);

	queryResult = tree.SearchRegister(key);

	ASSERT_EQ(queryResult.result->getValue().m_invertedListPosition, updated);
}

/**
 * Test Throw Exception on Old Constructor
 */

TEST_F( BPlusTreeFixedTestFixture, ThrowOldConstructorException )
{
	BPlusTreeFile* testFile =  new BPlusTreeFile(this->getFileNameForTest(), 2 * 64, true);

	ASSERT_ANY_THROW( BPlusTreeFixed tree( testFile ) );
}

/**
 * Test Throw Exception Key Does Not Exist
 */

TEST_F( BPlusTreeFixedTestFixture, ThrowOldKeyDoesNotExist )
{
	BPlusTreeFixed tree( this->getFileNameForTest(), 2 * 64, true );

	ASSERT_ANY_THROW( tree.UpdateRegister( string("KeyNoExiste"), 70 ) );
}

/**
 * Test Insert And get First
 */
TEST_F( BPlusTreeFixedTestFixture, InsertAndGetFirst)
{
	BPlusTreeFixed tree( this->getFileNameForTest(), 2 * 64, true );

	std::string  key = "asdqpojfwepf";

	tree.InsertRegister(key, {});
	tree.InsertRegister("brugoqrug", {});
	tree.InsertRegister("zzzzzzz", {});

	auto queryResult = tree.begin();

	ASSERT_EQ(queryResult.result->getKey(), key);
}


#endif /* BPLUSTREEFIXEDTEST_GTEST_H_ */
